package org.chipu.shared.util.singletons;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.logging.Level;

public class NetworkUtils {
	private final static Map<Byte, String> protocolMap = new HashMap<Byte, String>();
	private final static Map<Integer, String> portMap = new HashMap<Integer, String>();
	static {
		// protocolMap.put((byte) 3, "ip");
		protocolMap.put((byte) 1, "icmp");
		protocolMap.put((byte) 6, "tcp");
		protocolMap.put((byte) 17, "udp");

		portMap.put(25, "smtp");
		portMap.put(53, "dns");
		portMap.put(80, "http");
		portMap.put(443, "https");
		portMap.put(8080, "tomcat");
		portMap.put(8443, "tomcats");
	}

	private NetworkUtils() {/**/}

	public static String getActiveInterfaceName() {
		NetworkInterface ni = getActiveInterface();
		return ni == null? "": ni.getName();
	}

	public static NetworkInterface getActiveInterface() {
		try {
			for(NetworkInterface ni : Collections.list(NetworkInterface.getNetworkInterfaces()))
				if (ni.isUp() && !ni.isLoopback())
					return ni;
		} catch(SocketException e) {/**/
		}
		return null;
	}

	public static String getHostName() {
		try {
			InetAddress localMachine = InetAddress.getLocalHost();
			return localMachine.getHostName();
		} catch(UnknownHostException uhe) {
			// handle exception
		}
		return "";
	}

	public static NetworkAddress getLocalNetwork(String activeInterfaceName) {
		if (!OSUtils.isUnix())
			throw new UnsupportedOperationException();
		Process p = LinuxUtils.runCommand("ifconfig | awk -v \"RS=\\n\" '{print $1 \" \" $2 \" \" $4}'",
			true, false, true);
		BufferedReader d = new BufferedReader(new InputStreamReader(new DataInputStream(p.getInputStream())));
		String s = null;
		try {
			boolean flag = false;
			do {
				s = d.readLine();
				if (s == null)
					return null;
				String[] ss = s.split(" ");
				if (flag)
					return new NetworkAddress(ss[1].substring(5), ss[2].substring(5));
				if (ss[0].equals(activeInterfaceName))
					flag = true;
			} while(true);
		} catch(IOException ex) {
			LoggingUtils.getLogger().log(Level.SEVERE, "", ex);
			return null;
		}
	}

	public static String getIp(Long decimalIp) {
		long resto1 = decimalIp % 16777216;
		long resto2 = resto1 % 65536;
		long resto3 = resto2 % 256;
		return decimalIp / 16777216 + "." + resto1 / 65536 + "." + resto2 / 256 + "." + resto3;
	}

	public static long getIp(String dottedIp) {
		String[] s = dottedIp.split("\\.");
		if (s.length != 4)
			throw new IllegalArgumentException("Not valid as ipv4: " + dottedIp);
		return Long.parseLong(s[0]) * 16777216 + Long.parseLong(s[1]) * 65536 + Long.parseLong(s[2]) * 256
			+ Long.parseLong(s[3]);
	}

	public static String guessProtocolName(byte protocol) {
		return protocolMap.containsKey(protocol)? protocolMap.get(protocol): String.valueOf(protocol);
	}

	public static String guessPortName(int protocol) {
		return portMap.containsKey(protocol)? portMap.get(protocol): String.valueOf(protocol);
	}

	public static String getPortName(int protocol) {
		return portMap.containsKey(protocol)? portMap.get(protocol): null;
	}

	public static byte getProtocolCode(String protocol) {
		return protocolMap.containsValue(protocol)? getKey(protocolMap, protocol): -1;
	}

	private static <K, V> K getKey(Map<K, V> map, V value) {
		for(Entry<K, V> e : map.entrySet())
			if (value.equals(e.getValue()))
				return e.getKey();
		return null;
	}

	public static Collection<Byte> getKnownNetworkProtocols() {
		return protocolMap.keySet();
	}

	public static int getKnownNetworkProtocolsCount() {
		return protocolMap.size();
	}
}